import base64
import json
import logging
import pickle

from django import http
from django.shortcuts import render

# Create your views here.
from django.views import View
from django_redis import get_redis_connection

from goods.models import SKU
from meiduo_mall.utils.response_code import RETCODE

logger = logging.getLogger('django')


class CartsView(View):
    """购物车相关操作"""
    def post(self,request):
        """新增购物车数据"""
        # 获取前端传递axios中的数据
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get("sku_id")
        count = json_dict.get("count")
        selected = json_dict.get("selected", True)
        # 判断：1）校验参数是不是全；2）校验sku_id是否有；3）校验count格式是否对的；

        if all([sku_id, count, selected]) is False:
            return http.HttpResponseForbidden("参数不全")
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id不存在')
        try:
            count = int(count)
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('参数类型有误')
        if isinstance(selected,bool) is False:
            return http.HttpResponseForbidden('参数类型有误')

        # 判断用户是否登录：
        user = request.user
        if request.user.is_authenticated:
            # 1）已登录用户，将数据存储进redis;
            redis_conn = get_redis_connection('carts')
            p1 = redis_conn.pipeline()
            # A 、针对已经存在的stu_id则直接在count上加1,hincrby含有此功能；B、针对未存在的用户直接新增；格式如下：# { “carts_userid":{"sku_id1":count1,"sku_id2":count2,.. #hash  }
            p2 = p1.hincrby('carts_%s'% user.id, sku_id, count)
            print(p2)
            # selexted_userid":(stu_id 1 ,stu_id 2,......) #set}
            if selected:
                p3 = p1.sadd('selected_%s'% user.id, sku_id)
                print(p3)
            p1.execute()
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
        else:
            # 2)未登录用户：将数据存储进去cookies,需要将值加密转化为字符串的形式存在；格式如下：{"sku_id":{" count ":2," seleted“:True}}
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
                if sku_id in cart_dict:
                    origin_count = cart_dict[sku_id]['count']
                    count += origin_count
            else:
                cart_dict = {}
            cart_dict[sku_id] ={
                "count": count,
                "selected": selected
            }
            cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': '添加购物车成功'})
            response.set_cookie("carts",cart_str)
            return response

    def get(self,request):
        """获取购物车的数据"""
        user = request.user
        if user.is_authenticated:
            # 对于已登录用户，直接获取redis数据库的数据(hash,set)；
            redis_conn =get_redis_connection('carts')
            redis_carts = redis_conn.hgetall('carts_%s'% user.id)
            selected_ids = redis_conn.smembers('selected_%s' % user.id)
            cart_dict = {}
            for sku_id_bytes in redis_carts:
                cart_dict[int(sku_id_bytes)] = {
                    "count": int(redis_carts[sku_id_bytes]),
                    "selected": sku_id_bytes in selected_ids
                }

            # 对于未登录用户，获取cookies的数据；
        else:
            carts_str = request.COOKIES.get('carts')
            if carts_str:
                cart_dict = pickle.loads(base64.b64decode(carts_str.encode()))
            else:
                return render(request, 'cart.html')

            # 已登录与未登录均统一输出；从数据库中获取已有sku_id的数值
        sku_qs = SKU.objects.filter(id__in=cart_dict.keys())
        cart_skus = []
        for sku in sku_qs:
            count = cart_dict[sku.id]['count']
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'price': str(sku.price),
                'default_image_url': sku.default_image.url,
                'selected': str(cart_dict[sku.id]['selected']),
                'count': count,
                'amount': str(sku.price*count)
            })
        content ={
            "cart_skus": cart_skus,
        }
        return render(request, 'cart.html', content)

    def put(self,request):
        """更改购物车数量"""
        # 获取前端发起put请求中的数据
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        count = json_dict.get('count')
        selected = json_dict.get('selected',True)
        # 对数据进行校验
        if all([sku_id, count]) is False:
            return http.HttpResponseForbidden("参数不全")
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id不存在')
        try:
            count = int(count)
        except Exception as e:
            logger.error(e)
            return http.HttpResponseForbidden('参数类型有误')
        if isinstance(selected, bool) is False:
            return http.HttpResponseForbidden('参数类型有误')
        # 获取当前是否登录用户；
        user = request.user
        if user.is_authenticated:
        # 1）登录用户，则更新redis的数据
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            pl.hset('carts_%s'%user.id, sku_id, count)
            if selected:
                # 如果要勾选,就把当前sku_id添加到set中
                pl.sadd('selected_%s' % user.id, sku_id)
            else:
                # 不勾选时,把sku_id从set中移除
                pl.srem('selected_%s'% user.id, sku_id)
            pl.execute()

            sku = SKU.objects.get(id=sku_id)
            cart_sku = {
                'id': sku.id,
                'name': sku.name,
                'price': str(sku.price),
                'default_image_url': sku.default_image.url,
                'selected': selected,
                'count': count,
                'amount': str(sku.price * count)
            }
            context = {
                'cart_sku':cart_sku,
            }
            return http.JsonResponse({'code':RETCODE.OK,'errmsg':'OK','context':context})

        else:
        # 2）非登录用户，则更新cookie的数据；
            cart_str = request.COOKIES.get('carts')
            if cart_str:
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                return render(request,'cart.html')
            cart_dict[sku_id] = {
                'count': count,
                'selected':selected
            }
            # 将数据进行转码为字符串，重新更新cookie
            cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
            # 重新拼接数据，返回前端渲染新数据；
            sku = SKU.objects.get(id=sku_id)
            cart_sku = {
                'id': sku.id,
                'name': sku.name,
                'price': str(sku.price),
                'default_image_url': sku.default_image.url,
                'selected': selected,
                'count': count,
                'amount': str(sku.price * count)
            }
            response = http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'cart_sku': cart_sku})

            response.set_cookie('carts',cart_str)
        # 拼接数据返回并返回
            return response

    def delete(self,request):
        """删除购物车数据"""
        # 接收前端传过来的sku_id
        json_dict = json.loads(request.body.decode())
        sku_id = json_dict.get('sku_id')
        # 判断数据库中是否有该数据；
        try:
            sku = SKU.objects.get(id=sku_id)
        except SKU.DoesNotExist:
            return http.HttpResponseForbidden('sku_id不存在')

        user = request.user
        # 判断用户是否登录：
        if user.is_authenticated:
        # 1）已登录用户，删除redis数据；
            redis_conn = get_redis_connection('carts')
            pl = redis_conn.pipeline()
            pl.hdel('carts_%s'% user.id, sku_id)
            pl.srem('selected_%s' % user.id, sku_id)
            pl.execute()
            return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK'})

        # 2）未登录用户，删除cookie响应
        else:
            cart_str = request.COOKIES.get('carts')
            # 判断是否有cookie购物车数据
            if cart_str:
                # 把cookie字符串转字典
                cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
            else:
                # 如果没有取到cookie提前响应
                return render(request,'cart.html')
            # 删除cookie字典中的指定sku_id 键值对象
            if sku_id in cart_dict:
                del cart_dict[sku_id]
            response = http.JsonResponse({'code':RETCODE.OK,'errmsg':'删除成功'})
            # 如果cookie大字典已经没有商品了, 把cookie购物车数据直接删除
            if not cart_dict:
                response.delete_cookie('carts')
                return response
            # 把cookie字典转回字符串
            cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
            response.set_cookie('carts',cart_str)
            return response


class CartsSelectAllView(View):
    """购物车全选"""
    def put(self,request):
        # 接收前端的数据
        json_dict = json.loads(request.body.decode())
        selected = json_dict.get('selected')
        # 校验：
        if isinstance(selected, bool) is False:
            return http.HttpResponseForbidden('参数不对')
        # 校验用户是否登录
        user = request.user
        # 1）登录用户，如果是全选，则取hash中全部的sku_id，并加入到set集合中；
        # 如果是取消，直接删除set集合；
        if user.is_authenticated:
            redis_conn = get_redis_connection('carts')
            if selected:
                redis_carts = redis_conn.hgetall('carts_%s' % user.id)
                sku_ids = redis_carts.keys()
                redis_conn.sadd('selected_%s' % user.id, *sku_ids)  #请注意此处是很多个，需要加*
            else:
                redis_conn.delete('selected_%s' % user.id)
            return http.JsonResponse({'code':RETCODE.OK, 'errmsg': 'OK'})
        # 2）未登录用户，如果全选则将所有的seleted值改成true, 取消改成false;
        cart_str = request.COOKIES.get('carts')
        if cart_str:
            cart_dict = pickle.loads(base64.b64decode(cart_str.encode()))
        else:
            return http.JsonResponse({'code': RETCODE.DBERR, 'errmsg': '没有cookie'})
        for sku_id in cart_dict:
            cart_dict[sku_id] = {
                'count': cart_dict[sku_id]['count'],
                'selected': selected
            }
        cart_str = base64.b64encode(pickle.dumps(cart_dict)).decode()
        response = http.JsonResponse({'code': RETCODE.OK, 'errmsg':'OK'})
        response.set_cookie('carts', cart_str)
        return response


class CartsSimpleView(View):
    """详情页简单购物车展示"""
    def get(self,request):
        """获取购物车的数据"""
        user = request.user
        if user.is_authenticated:
            # 对于已登录用户，直接获取redis数据库的数据(hash,set)；
            redis_conn =get_redis_connection('carts')
            redis_carts = redis_conn.hgetall('carts_%s'% user.id)
            selected_ids = redis_conn.smembers('selected_%s' % user.id)
            cart_dict = {}
            for sku_id_bytes in redis_carts:
                cart_dict[int(sku_id_bytes)] = {
                    "count": int(redis_carts[sku_id_bytes]),
                    "selected": sku_id_bytes in selected_ids
                }

            # 对于未登录用户，获取cookies的数据；
        else:
            carts_str = request.COOKIES.get('carts')
            if carts_str:
                cart_dict = pickle.loads(base64.b64decode(carts_str.encode()))
            else:
                return render(request, 'cart.html')

            # 已登录与未登录均统一输出；从数据库中获取已有sku_id的数值
        sku_qs = SKU.objects.filter(id__in=cart_dict.keys())
        cart_skus = []
        for sku in sku_qs:
            count = cart_dict[sku.id]['count']
            cart_skus.append({
                'id': sku.id,
                'name': sku.name,
                'default_image_url': sku.default_image.url,
                'count': count,
            })

        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'cart_skus': cart_skus})











